package util

import (
	"database/sql"
	_ "github.com/lib/pq"
	"golang.org/x/text/cases"
	"golang.org/x/text/language"
	"ubt-rbac-service/internal/core/config"
	"ubt-rbac-service/internal/core/logger"
	"strings"
)

var dbConn *sql.DB

// InitPgsql 连接MySQL数据库
func InitPgsql() *sql.DB {
	cfg := config.GetConfig()
	var err error
	dataSrcName := "host=" + cfg.DbConfig.DbHost + " port=" + cfg.DbConfig.DbPort + " user=" + cfg.DbConfig.Usname + " password=" + cfg.DbConfig.Passwd + " dbname=" + cfg.DbConfig.DbName + " sslmode=disable"
	if dbConn, err = sql.Open("postgres", dataSrcName); err == nil {
		if err = dbConn.Ping(); err != nil {
			logger.Error("连接数据库失败。" + err.Error())
			return nil
		}
		return dbConn
	}
	logger.Error("初始化数据库失败。" + err.Error())
	return nil
}

// GetDbConn 获取全局的数据库连接信息
func GetDbConn() *sql.DB {
	if dbConn == nil {
		InitPgsql()
	}
	return dbConn
}

// CudData 操作数据，增、删、改均调用该方法
func CudData(sqlStr string, args ...interface{}) (uint32, string) {
	logger.Debug(sqlStr)
	logger.Debug(args...)
	stmt, err := dbConn.Prepare(sqlStr)
	defer stmtClose(stmt)
	if err == nil {
		if _, err = stmt.Exec(args...); err == nil {
			return 1001, "ok"
		} else {
			logger.Error("数据处理失败。" + err.Error())
			return 1002, "数据处理失败"
		}
	} else {
		logger.Error("操作数据预处理失败。" + err.Error())
		return 1003, "操作数据预处理失败"
	}
}

// stmtClose 关闭预处理对象
func stmtClose(stmt *sql.Stmt) {
	if err := stmt.Close(); err != nil {
		logger.Error("关闭预处理对象失败。" + err.Error())
	}
}

// rowsClose 关闭行对象
func rowsClose(row *sql.Rows) {
	if err := row.Close(); err != nil {
		logger.Error("关闭预处理对象失败。" + err.Error())
	}
}

// GetOne 获取一行记录
func GetOne(sqlStr string, args ...interface{}) (map[string]interface{}, error) {
	logger.Debug(sqlStr)
	logger.Debug(args...)
	rows, err := dbConn.Query(sqlStr, args...)
	defer rowsClose(rows)
	if err == nil {
		var res map[string]interface{}
		for rows.Next() {
			res, err = scanRow(rows)
			if err != nil {
				logger.Error("数据转换失败。" + err.Error())
			}
			break
		}
		return res, nil
	} else {
		logger.Error("数据获取失败。" + err.Error())
		return nil, err
	}
}

// GetAll 获取多行记录
func GetAll(sqlStr string, args ...interface{}) ([]map[string]interface{}, error) {
	logger.Debug(sqlStr)
	logger.Debug(args...)
	rows, err := dbConn.Query(sqlStr, args...)
	defer rowsClose(rows)
	if err == nil {
		result := make([]map[string]interface{}, 0)
		var (
			res  map[string]interface{}
			flag uint8
		)
		for rows.Next() {
			if res, err = scanRow(rows); err == nil {
				result = append(result, res)
			} else {
				flag = 1
				logger.Error("数据转换失败。" + err.Error())
				break
			}
		}
		if flag == 1 {
			return nil, err
		} else {
			return result, nil
		}
	} else {
		return nil, err
	}
}

// scanRow 将数据库字段转换为Map
func scanRow(rows *sql.Rows) (map[string]interface{}, error) {
	if columns, err := rows.Columns(); err == nil {
		vals := make([]interface{}, len(columns))
		valsPtr := make([]interface{}, len(columns))
		for i := range vals {
			valsPtr[i] = &vals[i]
		}
		if err = rows.Scan(valsPtr...); err == nil {
			r := make(map[string]interface{})
			c := cases.Title(language.Dutch)
			for i, v := range columns {
				// 将数据表中各字段下划线转成驼峰
				v = strings.Replace(v, "_", " ", -1)
				v = c.String(v)
				v = strings.Replace(v, " ", "", -1)
				v = strings.ToLower(string(v[0])) + v[1:]
				if va, ok := vals[i].([]byte); ok {
					r[v] = string(va)
				} else {
					r[v] = vals[i]
				}
			}
			return r, nil
		} else {
			logger.Error("数据转换失败。" + err.Error())
			return nil, err
		}
	} else {
		logger.Error("获取数据表字段失败。" + err.Error())
		return nil, err
	}
}
